#ifndef __H_MATCHER_M__
#define  __H_MATCHER_M__

#include "util.hpp"
#include "db.hpp"
#include "room.hpp"
#include <list>
#include <thread>
#include <condition_variable>

template<class T>
class match_queue
{
public:
    void push(const T& data)
    {
        unique_lock<mutex> lock(_mutex);
        _queue.push_back(data);
        _cond.notify_all();
    }
    bool pop(T& data)
    {
        unique_lock<mutex> lock(_mutex);

        if(_queue.empty())
            { return false;}

        data = _queue.front();
        _queue.pop_front();

        return true;
    }
    int size() {  return _queue.size(); }
    bool empty()  { return _queue.empty();  }
    void wait()
    {
        unique_lock<mutex> lock(_mutex);
        _cond.wait(lock);
    }
    void remove(T& data)
    {
        unique_lock<mutex> lock(_mutex);
        _queue.remove(data);
    }

private:
    list<T> _queue;
    mutex _mutex;
    condition_variable _cond;
};


class matcher
{
public:
    matcher(user_table* ut, online_manager* om, room_manager* rm)
        :_ut(ut), _om(om), _rm(rm)
        ,_th_rookie(&matcher::th_rookie_entry,this)
        ,_th_expert(&matcher::th_expert_entry,this)
        ,_th_guru(&matcher::th_guru_entry,this)
    { DLOG("匹配管理模块初始化完成！"); }

    bool add(uint64_t uid)
    {
        Json::Value user;
        if(_ut->select_by_id(uid, user) == false)
        {
            ELOG("获取%d用户信息失败！", uid);
            return false;
        }
        int score = user["score"].asInt();
        if(score < 2000)
            {  _qe_rookie.push(uid);  }
        else if(2000 <= score &&  score < 3000)
            { _qe_expert.push(uid); }
        else
            {  _qe_guru.push(uid); }

        return true;
    }
    bool del(uint64_t uid)
    {
        Json::Value user;
        if(_ut->select_by_id(uid, user) == false)
        {
            ELOG("获取%d用户信息失败！", uid);
            return false;
        }
        int score = user["score"].asInt();
        if(score < 2000 )
            { _qe_rookie.remove(uid); }
        else if(2000 <= score &&  score < 3000)
            { _qe_expert.remove(uid); }
        else 
            { _qe_guru.remove(uid); }
        
        return true;
    }
private:
    void handle_matche(match_queue<uint64_t>& mq)
    {
        while(true)
        {
            // 1. 队列中的玩家是否 < 2 ，小于2就阻塞
            while(mq.size() < 2)
                { mq.wait(); }

            // 2. 把两个玩家拿出队列
            uint64_t uid1, uid2;
            if(mq.pop(uid1) == false)
                { continue; }
            if(mq.pop(uid2) == false)
            {
                // mq.push(uid1);
                this->add(uid1);
                continue;
            }
            // 3. 校验玩家是否都在线，如果有一个不在，把另一个放回队列
            wsserver_t::connection_ptr conn1 = _om->get_conn_form_hall(uid1);
            if(conn1.get() == nullptr)
            {
                // mq.push(uid2);
                this->add(uid2);

                continue;
            }
            wsserver_t::connection_ptr conn2 = _om->get_conn_form_hall(uid2);
            if(conn2.get() == nullptr)
            {
                // mq.push(uid1);
                this->add(uid1);
                continue;
            }
            // 4. 为玩家创建游戏房间，将玩家加入游戏房间
            room_ptr rp = _rm->create_room(uid1, uid2);
            if(rp.get() == nullptr)
            {
                // mq.push(uid1);
                // mq.push(uid2);
                this->add(uid1);
                this->add(uid2);

                continue;
            }
            // 5. 对玩家进行响应
            Json::Value resp;
            resp["optype"] = "match_success";
            resp["result"] = true;
            string body;
            json_util::serialize(resp, body);
            conn1->send(body);
            conn2->send(body);
        }
        
    }

    void th_rookie_entry() { return handle_matche(_qe_rookie); }
    void th_expert_entry() { return handle_matche(_qe_expert); }
    void th_guru_entry() { return handle_matche(_qe_guru); }
private:
    match_queue<uint64_t> _qe_rookie;
    match_queue<uint64_t> _qe_expert;
    match_queue<uint64_t> _qe_guru;
    thread _th_rookie;
    thread _th_expert;
    thread _th_guru;
    user_table* _ut;
    online_manager* _om;
    room_manager* _rm;
};

#endif